package codecs;

import java.awt.Dimension;

import javax.media.Buffer;
import javax.media.Codec;
import javax.media.Format;
import javax.media.ResourceUnavailableException;
import javax.media.format.RGBFormat;
import javax.media.format.VideoFormat;
import javax.media.format.YUVFormat;

/**
 * Calculates the reactangle, in which the detection is performed, and draws it on
 * the stream.
 * @author	Daniel Mohr, Daniela Grammlich
 */
public class BorderCodec implements Codec {
	
	/**
	 * The supported input formats
	 */
	protected Format[] supportedInputFormats = new Format[0];
	/**
	 * The supported output formats
	 */
	protected Format[] supportedOutputFormats = new Format[0];
	
	/**
	 * The input format
	 */
	protected VideoFormat inputFormat;
	/**
	 * The output format
	 */
	protected VideoFormat outputFormat;

	/**
	 * Defines the color white as hex value
	 */
	private static int white = 0x00ffffff;
	/**
	 * Defines the alpha channel
	 */
	private static double alphaChannel = 0.2;
	
	/**
	 * The name of the codec
	 */
	private static String CODEC_NAME = "BorderCodec";
	/**
	 * Control to access the BorderCodec data
	 */
	private BorderCodecControl borderCodecControl = new BorderCodecControl();
	
	public BorderCodec() {
		supportedInputFormats = new Format[] {
				new VideoFormat(VideoFormat.RGB, new Dimension(320, 240), 
						230400, Format.byteArray, (float) 15.0),
				new RGBFormat(),
				new YUVFormat(),
		};	
		supportedOutputFormats = new Format[] {
//				new VideoFormat(VideoFormat.RGB)
				new RGBFormat(),
				new YUVFormat(),
		};	
	}

	@Override
	public Format[] getSupportedInputFormats() {
		return supportedInputFormats;
	}

	@Override
	public Format[] getSupportedOutputFormats(Format input) {
		if(input == null) {
			return supportedOutputFormats;
		}
		if(input instanceof RGBFormat) {
			return(new Format[] {   
				input,
				supportedOutputFormats[0],
			});
		} else {
			return(supportedOutputFormats);
		}
	}

	@Override
	public synchronized int process(Buffer inputBuffer, Buffer outputBuffer) {
		outputBuffer.copy(inputBuffer);
		int outputDataLength = ((VideoFormat) outputFormat).getMaxDataLength();
		
		outputBuffer.setLength(outputDataLength);
		outputBuffer.setFormat(outputFormat);
		outputBuffer.setFlags(inputBuffer.getFlags());
		
		int[] outputData = (int[]) outputBuffer.getData();
		
		/* Getting the RGB masks of the stream */
		RGBFormat videoFormatIn = (RGBFormat) inputBuffer.getFormat();
		int redMask = videoFormatIn.getRedMask();
		int blueMask = videoFormatIn.getBlueMask();
		int greenMask = videoFormatIn.getGreenMask();
		
		/* Dimension of the incoming stream */
		Dimension sizeIn = videoFormatIn.getSize();
		int height = (int) sizeIn.getHeight();
		int width = (int) sizeIn.getWidth();
		
		/* Calculates size and position for the rectangle */
		borderCodecControl.setRectHeight((int) (height * 0.75));
		borderCodecControl.setRectWidth((int) (width * 0.5));
		borderCodecControl.setOffsetX((int) (width * 0.25));
		borderCodecControl.setOffsetY((int) (height * 0.125));
		
		int offsetBuffer, pixelData;

		/* Draw the rectangle */
		for(int y = 0; y < borderCodecControl.getRectHeight(); y++) {
			for(int x = 0; x < borderCodecControl.getRectWidth(); x++) {
				offsetBuffer = (y + borderCodecControl.getOffsetY()) * width + 
						borderCodecControl.getOffsetX() + x;
				pixelData = ((int)((outputData[offsetBuffer] & redMask) * 
						(1 - alphaChannel) + white * (alphaChannel))) & redMask;
				pixelData += ((int)((outputData[offsetBuffer] & greenMask) * 
						(1 - alphaChannel) + white * (alphaChannel))) & greenMask;
				pixelData += ((int)((outputData[offsetBuffer] & blueMask) * 
						(1 - alphaChannel) + white * (alphaChannel))) & blueMask;
				outputData[offsetBuffer] = pixelData;
			}
		}
		
		return BUFFER_PROCESSED_OK;
	}
	
	@Override
	public Format setInputFormat(Format inputFormat) {
		this.inputFormat = (VideoFormat) inputFormat;
		return (Format) this.inputFormat;
	}

	@Override
	public Format setOutputFormat(Format outputFormat) {
		this.outputFormat = (VideoFormat) outputFormat;
		return (Format) this.outputFormat;
	}

	@Override
	public void close() {
	}

	@Override
	public String getName() {
		return CODEC_NAME;
	}

	@Override
	public void open() throws ResourceUnavailableException {
	}

	@Override
	public void reset() {
		close();
//		open();
	}

	@Override
	public Object getControl(String controlType) {
		return borderCodecControl;
	}

	@Override
	public Object[] getControls() {
		Object[] controls = {
				borderCodecControl,
		};
		return controls;
	}

}
